﻿#region Disclaimer / License
// Copyright (C) 2011, Kenneth Bergeron, IAP Worldwide Services, Inc
// NOAA :: National Marine Fisheries Service
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
// 
#endregion
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Windows.Forms;

namespace CatchProcessing
{
    using LocalDataSet = DataSets.LocalDataSet;
    /// <summary>
    /// Support for taxonomy
    /// </summary>
    public static class Taxonomy
    {
        /// <summary>
        /// Kinds of lists
        /// </summary>
        public enum TaxonomyLevel
        {
            Recent = 0,
            Common = 1,
            Full = 2,
        }
        // Backing store
        private static bool itsLoaded = false;
        /// <summary>
        /// Is the taxonomy loading?
        /// </summary>
        public static bool Loading { get { return Loader != null && Loader.IsBusy; } }
        /// <summary>
        /// Is it loaded?
        /// </summary>
        public static bool Loaded { get { return itsLoaded; } private set { itsLoaded = value; } }
        /// <summary>
        /// Used to load the Taxon database
        /// </summary>
        private static System.ComponentModel.BackgroundWorker Loader = null;
        /// <summary>
        /// The taxonomy lists by level
        /// </summary>
        public static Dictionary<TaxonomyLevel, TaxBinding> Taxons = new Dictionary<TaxonomyLevel, TaxBinding>();
        /// <summary>
        /// Starts a background worker that loads the Full and Common taxonomy lists
        /// </summary>
        /// <param name="aFish"></param>
        public static void LoadTax()
        {
            if (Loaded || Loader != null) return;
            Loader = new System.ComponentModel.BackgroundWorker();
            Loader.DoWork += new System.ComponentModel.DoWorkEventHandler(
                delegate(object sender, System.ComponentModel.DoWorkEventArgs e)
                {
                    LocalLoadTax();
                    Loaded = true;
                });
            Loader.RunWorkerAsync();
        }
        /// <summary>
        /// If loading, idle loop until finished
        /// </summary>
        public static void WaitForLoader()
        {
            // Nothing to wait for
            if (Loader == null) return;
            while (Loader.IsBusy)
            {
                System.Threading.Thread.Sleep(100);
                Application.DoEvents();
            }
        }
        /// <summary>
        /// reload
        /// </summary>
        public static void ReloadTax()
        {
            Loaded = false;
            Taxonomy.LoadTax();
        }
        /// <summary>
        /// Stores a Taxonomy list
        /// </summary>
        public class Taxon
        {
            /// <summary>
            /// TRSN
            /// </summary>
            public string TRSN { get; set; }
            /// <summary>
            /// Taxonomy, description, name...
            /// </summary>
            public string Taxonomy { get; set; }
            /// <summary>
            /// Parsed ok
            /// </summary>
            public bool OK = false;
            /// <summary>
            /// ctor
            /// </summary>
            /// <param name="aTRSN">TRSN</param>
            /// <param name="aTaxon">Taxon</param>
            public Taxon(string aTRSN, string aTaxon)
            {
                TRSN = aTRSN;
                Taxonomy = aTaxon;
                OK = true;
            }
            /// <summary>
            /// ctor with a CSV line
            /// </summary>
            /// <param name="aCSVLine">CSV TRSN,Taxonomy</param>
            public Taxon(string aCSVLine)
            {
                string[] Parts = aCSVLine.Split(',');
                if (Parts.Length != 2) return;
                TRSN = Parts[0];
                Taxonomy = Parts[1];
                OK = true;
            }
            public new string ToString()
            {
                return this.Taxonomy;
            }
        }
        /// <summary>
        /// Taxonomy for easy control binding
        /// </summary>
        public class TaxBinding : System.ComponentModel.BindingList<Taxon>
        {
            /// <summary>
            /// Used to lookup Taxonomy given TRSN
            /// </summary>
            public Dictionary<string, string> TRSNByTaxon = new Dictionary<string, string>();
            /// <summary>
            /// Used to lookup TRSN given Taxonomy
            /// </summary>
            public Dictionary<string, string> TaxonByTRSN = new Dictionary<string, string>();
            /// <summary>
            /// ctor
            /// </summary>
            /// <param name="aByTRSN">Contents</param>
            public TaxBinding(Dictionary<string, Taxon> aByTRSN)
                : base(aByTRSN.Values.OrderBy(qR=>qR.Taxonomy).ToList())
            {
                TaxonByTRSN = aByTRSN.ToDictionary(qK => qK.Value.TRSN, qV => qV.Value.Taxonomy);
                TRSNByTaxon = aByTRSN.ToDictionary(qK => qK.Value.Taxonomy, qV => qV.Value.TRSN);
            }
            /// <summary>
            /// ctor
            /// </summary>
            /// <param name="aFishTable">Fish database</param>
            public TaxBinding(LocalDataSet.FishDataTable aFishTable) : base()
            {
                foreach (Taxon T in aFishTable.Select(qR => new Taxon(qR.TRSN, qR.Species)).OrderBy(qR=>qR.Taxonomy))
                    TaxonByTRSN[T.TRSN] = T.Taxonomy;
                foreach (KeyValuePair<string, string> kvp in TaxonByTRSN)
                    Add(new Taxon(kvp.Key, kvp.Value));
            }
            /// <summary>
            /// Find TRSN
            /// </summary>
            /// <param name="aTaxon">Taxonomy</param>
            /// <returns>TRSN</returns>
            public string FindTRSN(string aTaxon)
            {
                if (this.TRSNByTaxon.ContainsKey(aTaxon.ToUpper())) return this.TRSNByTaxon[aTaxon];
                return aTaxon;
            }
            /// <summary>
            /// Find Taxonomy
            /// </summary>
            /// <param name="aTRSN">TRSN</param>
            /// <returns>Taxonomy</returns>
            public string FindTaxon(string aTRSN)
            {
                if (this.TaxonByTRSN.ContainsKey(aTRSN)) return this.TaxonByTRSN[aTRSN];
                return aTRSN;
            }
        }
        /// <summary>
        /// Load the Recent list from the database
        /// </summary>
        /// <param name="aFish"></param>
        public static void LoadRecent(LocalDataSet.FishDataTable aFish)
        {
            Taxons[TaxonomyLevel.Recent] = new TaxBinding(aFish);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="aCSVFileName"></param>
        /// <returns></returns>
        private static Dictionary<string, Taxon> FromCSV(string aCSVFileName)
        {
            Dictionary<string, Taxon> Result = new Dictionary<string, Taxon>();
            using (System.IO.TextReader tr = new System.IO.StreamReader(aCSVFileName))
            {
                tr.ReadLine();      // Skip the CSV line...
                while (tr.Peek() > 0)
                {
                    Taxon NewOne = new Taxon(tr.ReadLine());
                    if (NewOne.OK) Result[NewOne.TRSN] = NewOne;
                }
            }
            return Result;
        }
        /// <summary>
        /// Loads the Full and Common Taxonomy lists
        /// </summary>
        public static void LocalLoadTax()
        {
            string App = System.IO.Path.GetDirectoryName(Application.ExecutablePath);
            Taxons[TaxonomyLevel.Common] = new TaxBinding(
                FromCSV(System.IO.Path.Combine(App, "StaticData", "LL-ShortList.csv")));
            Taxons[TaxonomyLevel.Full] = new TaxBinding(
                FromCSV(System.IO.Path.Combine(App, "StaticData", "Full-Listing.csv")));
        }
    }
}
